"""
日志过滤器。

提供各种日志过滤器，用于根据不同的规则筛选日志记录，
支持模块级别过滤、组件级别过滤等。
"""

import logging
import re
from typing import Dict, List, Optional, Pattern, Set, Union


class ModuleFilter(logging.Filter):
    """
    基于模块路径筛选日志记录。

    可以包含或排除指定的模块路径。
    """

    def __init__(
        self,
        name: str = "",
        include_modules: List[str] = None,
        exclude_modules: List[str] = None,
    ):
        """
        初始化模块过滤器。

        Args:
            name: 过滤器名称
            include_modules: 要包含的模块路径列表，优先级高于exclude
            exclude_modules: 要排除的模块路径列表
        """
        super().__init__(name)
        self.include_modules = set(include_modules or [])
        self.exclude_modules = set(exclude_modules or [])

    def filter(self, record: logging.LogRecord) -> bool:
        """
        过滤日志记录。

        Args:
            record: 日志记录对象

        Returns:
            bool: 是否保留此记录
        """
        module_name = record.name

        # 如果指定了包含模块，检查是否匹配
        if self.include_modules:
            for include in self.include_modules:
                if module_name == include or module_name.startswith(f"{include}."):
                    return True
            # 如果指定了包含但不匹配，排除
            return False

        # 如果指定了排除模块，检查是否匹配
        if self.exclude_modules:
            for exclude in self.exclude_modules:
                if module_name == exclude or module_name.startswith(f"{exclude}."):
                    return False

        # 默认包含
        return True


class LevelRangeFilter(logging.Filter):
    """
    基于日志级别范围筛选日志记录。

    可以设置最小和最大级别，只保留在范围内的记录。
    """

    def __init__(
        self,
        min_level: Union[int, str] = logging.DEBUG,
        max_level: Union[int, str] = logging.CRITICAL,
    ):
        """
        初始化级别范围过滤器。

        Args:
            min_level: 最小日志级别，可以是整数级别或字符串名称
            max_level: 最大日志级别，可以是整数级别或字符串名称
        """
        super().__init__()

        # 处理字符串级别
        if isinstance(min_level, str):
            min_level = getattr(logging, min_level.upper(), logging.DEBUG)
        if isinstance(max_level, str):
            max_level = getattr(logging, max_level.upper(), logging.CRITICAL)

        self.min_level = min_level
        self.max_level = max_level

    def filter(self, record: logging.LogRecord) -> bool:
        """
        过滤日志记录。

        Args:
            record: 日志记录对象

        Returns:
            bool: 是否保留此记录
        """
        return self.min_level <= record.levelno <= self.max_level


class RegexFilter(logging.Filter):
    """
    基于正则表达式筛选日志记录。

    可以根据消息内容过滤日志记录。
    """

    def __init__(self, pattern: Union[str, Pattern], include: bool = True):
        """
        初始化正则表达式过滤器。

        Args:
            pattern: 正则表达式模式，可以是字符串或已编译的正则表达式对象
            include: True表示匹配时保留，False表示匹配时排除
        """
        super().__init__()
        self.pattern = re.compile(pattern) if isinstance(pattern, str) else pattern
        self.include = include

    def filter(self, record: logging.LogRecord) -> bool:
        """
        过滤日志记录。

        Args:
            record: 日志记录对象

        Returns:
            bool: 是否保留此记录
        """
        message = record.getMessage()
        match = bool(self.pattern.search(message))
        # 根据include标志决定是保留还是排除匹配项
        return match if self.include else not match


class DuplicateFilter(logging.Filter):
    """
    过滤重复的日志消息。

    防止在短时间内打印相同的日志消息。
    """

    def __init__(self, max_repeated: int = 1, time_window: float = 5.0):
        """
        初始化重复过滤器。

        Args:
            max_repeated: 允许的最大重复次数
            time_window: 时间窗口（秒）
        """
        super().__init__()
        self.max_repeated = max_repeated
        self.time_window = time_window
        self.last_logs = {}  # 消息 -> (时间, 计数)

    def filter(self, record: logging.LogRecord) -> bool:
        """
        过滤日志记录。

        Args:
            record: 日志记录对象

        Returns:
            bool: 是否保留此记录
        """
        import time

        # 获取当前时间和消息
        current_time = time.time()
        message = record.getMessage()

        # 检查是否是重复消息
        if message in self.last_logs:
            last_time, count = self.last_logs[message]

            # 如果在时间窗口内且已达到最大重复次数，则过滤
            if (
                current_time - last_time < self.time_window
                and count >= self.max_repeated
            ):
                return False

            # 更新计数
            if current_time - last_time < self.time_window:
                self.last_logs[message] = (last_time, count + 1)
            else:
                # 如果超出时间窗口，重置计数
                self.last_logs[message] = (current_time, 1)
        else:
            # 首次出现的消息
            self.last_logs[message] = (current_time, 1)

        return True


class ModuleLevelFilter(logging.Filter):
    """
    根据模块名称和级别过滤日志。

    允许为不同模块设置不同的日志级别。
    """

    def __init__(self, module_levels: Dict[str, int]):
        """
        初始化模块级别过滤器。

        Args:
            module_levels: 模块名称到日志级别的映射，例如：
                {"continuallearning.models.pefts": logging.INFO}
        """
        super().__init__()
        self.module_levels = module_levels

    def filter(self, record: logging.LogRecord) -> bool:
        """
        根据模块名称和配置的级别过滤日志记录。

        Args:
            record: 日志记录对象

        Returns:
            bool: 是否保留此日志记录
        """
        # 默认保留
        should_log = True

        # 寻找最具体的匹配模块
        matching_module = ""
        for module_name, level in self.module_levels.items():
            # 检查记录是否来自该模块或其子模块
            if record.name.startswith(module_name) and len(module_name) > len(
                matching_module
            ):
                matching_module = module_name
                # 如果日志级别低于该模块的配置级别，则过滤掉
                if record.levelno < level:
                    should_log = False
                else:
                    should_log = True

        return should_log


class ComponentFilter(logging.Filter):
    """
    根据组件名称过滤日志。

    允许只显示特定组件的日志，或排除特定组件的日志。
    """

    def __init__(
        self, include: Optional[List[str]] = None, exclude: Optional[List[str]] = None
    ):
        """
        初始化组件过滤器。

        Args:
            include: 要包含的组件名称列表，如果为None则包含所有
            exclude: 要排除的组件名称列表，如果为None则不排除任何组件
        """
        super().__init__()
        self.include = set(include) if include else None
        self.exclude = set(exclude) if exclude else set()

    def filter(self, record: logging.LogRecord) -> bool:
        """
        根据组件名称过滤日志记录。

        Args:
            record: 日志记录对象

        Returns:
            bool: 是否保留此日志记录
        """
        # 提取组件名称（通常是模块层级的第一部分）
        name_parts = record.name.split(".")
        component = name_parts[0] if name_parts else ""

        # 如果组件在排除列表中，则过滤掉
        if component in self.exclude:
            return False

        # 如果有包含列表，则只保留列表中的组件
        if self.include is not None:
            return component in self.include

        # 默认保留
        return True


class ContextFilter(logging.Filter):
    """
    支持添加上下文信息到日志记录的过滤器。

    不过滤任何记录，但会向记录添加额外上下文信息。
    """

    def __init__(self, context: Dict[str, any] = None):
        """
        初始化上下文过滤器。

        Args:
            context: 要添加到每条日志记录的上下文信息
        """
        super().__init__()
        self.context = context or {}

    def filter(self, record: logging.LogRecord) -> bool:
        """
        向日志记录添加上下文信息。

        Args:
            record: 日志记录对象

        Returns:
            bool: 始终为True，不过滤任何记录
        """
        # 将上下文信息添加到记录的props中
        if not hasattr(record, "props"):
            record.props = {}

        record.props.update(self.context)
        return True


# 用于创建过滤器的工厂函数
def create_filter(filter_type: str, **kwargs) -> logging.Filter:
    """
    创建指定类型的过滤器。

    Args:
        filter_type: 过滤器类型，可选值：'module', 'level', 'regex', 'duplicate'
        **kwargs: 传递给特定过滤器的额外参数

    Returns:
        logging.Filter: 创建的过滤器

    Raises:
        ValueError: 如果指定了无效的过滤器类型
    """
    if filter_type == "module":
        return ModuleFilter(**kwargs)
    elif filter_type == "level":
        return LevelRangeFilter(**kwargs)
    elif filter_type == "regex":
        return RegexFilter(**kwargs)
    elif filter_type == "duplicate":
        return DuplicateFilter(**kwargs)
    else:
        raise ValueError(f"不支持的过滤器类型: {filter_type}")
